﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Demo.CommonBase.Logging;
using Demo.CommonBase.Exceptions;
using System.Reflection;

namespace Demo.Services.Services.Impl.DomainObjects.Helppers
{
    public class XMLHelper
    {
        /// <summary>
        /// Metodo que obtiene XML
        /// </summary>
        /// <typeparam name="C"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string GetXML<C>(C entity)
        {
            StringBuilder str;
            string valor;
            string root;
            string returnCad = null;
            int n;
            object item;
            object[] index;
            try
            {
                Logger.Info();
                root = "<Root>{0}</Root>"; //GetAttributeRoot<C>();
                str = new StringBuilder();
                if (entity.GetType().IsGenericType)
                {
                    n = (int)entity.GetType().GetProperty("Count").GetValue(entity, null);
                    index = new object[1];
                    for (int i = 0; i < n; i++)
                    {
                        // Get the list element as type object   
                        index[0] = i;
                        item = entity.GetType().GetProperty("Item").GetValue(entity, index);
                        valor = item.GetType().IsGenericType ? ConvertListToXml(item, false) : ConvertObjectToXml(item, false);
                        str.Append(valor);
                    }
                }
                else
                {
                    valor = ConvertObjectToXml(entity, false);
                    str.Append(valor);
                }
                returnCad = string.Format(root, str);
            }           
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw new UnhandledException(MethodBase.GetCurrentMethod(), ex);
            }
            return returnCad;
        }

        /// <summary>
        /// Metodo convirte una lista a xml
        /// </summary>
        /// <param name="list"></param>
        /// <param name="isProperty"></param>
        /// <returns></returns>
        private static string ConvertListToXml(object list, bool isProperty)
        {
            StringBuilder str;
            string valor;
            string root;
            string returnCad = null;
            int n;
            object item;
            object[] index;

            try
            {
                Logger.Info();
                if (list != null)
                {
                    n = (int)list.GetType().GetProperty("Count").GetValue(list, null);
                    index = new object[1];
                    str = new StringBuilder();
                    root = GetAttributeRoot(list, true);//GetAttributeRoot<object>();
                    for (int i = 0; i < n; i++)
                    {
                        // Get the list element as type object   
                        index[0] = i;
                        item = list.GetType().GetProperty("Item").GetValue(list, index);

                        if (item.GetType().IsGenericType)
                        {
                            valor = ConvertListToXml(item, false);
                        }
                        else
                        {
                            valor = ConvertObjectToXml(item, false);
                        }
                        str.Append(valor);
                    }
                    returnCad = isProperty ? str.ToString() : string.Format(root, str);
                }

            }         
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw new UnhandledException(MethodBase.GetCurrentMethod(), ex);
            }
            return returnCad;
        }

        /// <summary>
        /// Metodo convierte un objeto a xml
        /// </summary>
        /// <param name="item"></param>
        /// <param name="isProperty"></param>
        /// <returns></returns>
        private static string ConvertObjectToXml(object item, bool isProperty)
        {
            IList<PropertyInfo> props;
            PropertyInfo propsInfo;
            StringBuilder str;
            string node;
            string valor = string.Empty;
            string root;
            string returnCad = null;
            object valueItem;
            try
            {
                Logger.Info();
                if (item != null)
                {
                    props = GetProperties(item);

                    root = GetAttributeRoot(item, false); //GetAttributeRoot<object>();

                    str = new StringBuilder();
                    node = "<{0}>{1}</{0}>";
                    string name;
                    if (item.GetType().Namespace == "System")
                    {
                        valor = item.ToString();
                        str.Append(valor);
                    }
                    else
                    {
                        for (int i = 0; i < props.Count; i++)
                        {
                            propsInfo = props[i];
                            name = propsInfo.Name;

                            if (propsInfo.PropertyType.Namespace == "System")
                            {
                                valueItem = item.GetType().GetProperty(propsInfo.Name).GetValue(item, null);
                                if (valueItem != null)
                                {
                                    valor = valueItem.ToString();
                                }
                            }
                            else
                            {
                                valueItem = item.GetType().GetProperty(propsInfo.Name).GetValue(item, null);
                                valor = propsInfo.PropertyType.IsGenericType
                                            ? ConvertListToXml(valueItem, true)
                                            : ConvertObjectToXml(valueItem, true);
                            }

                            str.Append(string.Format(node, name, valor));
                        }
                    }
                    returnCad = isProperty ? str.ToString() : string.Format(root, str);
                }

            }          
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw new UnhandledException(MethodBase.GetCurrentMethod(), ex);
            }
            return returnCad;
        }


        /// <summary>
        /// Get the properties of entity
        /// </summary>
        /// <typeparam name="C">entity</typeparam>
        /// <param name="entity">entity object</param>
        /// <returns>properties</returns>
        private static IList<PropertyInfo> GetProperties<C>(C entity)
        {
            PropertyInfo[] props;
            List<PropertyInfo> propsList;
            propsList = new List<PropertyInfo>();
            try
            {
                props = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
                propsList.AddRange(props);
            }
            catch (Exception ex)
            {
                throw new Exception("Error generating properties", ex);
            }

            return propsList;
        }

        /// <summary>
        /// Metodo que crea el nodo
        /// </summary>
        /// <param name="item"></param>
        /// <param name="isList"></param>
        /// <returns></returns>
        private static string GetAttributeRoot(object item, bool isList)
        {
            string root = String.Empty;
            string name;
            string node;
            string[] strings;
            try
            {
                name = item.GetType().Name;
                if (isList)
                {
                    name = item.GetType().FullName;
                    name = name.Substring(name.IndexOf("[") + 2);
                    strings = name.Substring(0, name.IndexOf(",")).Split(new[] { '.' });
                    name = strings[strings.Length - 1];
                    name = string.Format("{0}{1}", name, "List");
                }
                node = "<{0}>{1}</{0}>";
                root = String.Format(node, name, "{0}");
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return root;
        }
    }
}
